package ln.gather.jsr.common.util;

import java.util.*;

/**
 * @Description 反序列化器
 * @Author zhangj
 * @Date 2022/11/12 23:42
 */
public class Deserializers {

    private final Map<Class<?>, List<Deserializer>> typeDeserializers = new HashMap<>();

    private final ClassLoader classLoader;

    public Deserializers(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public Deserializers() {
        this(Thread.currentThread().getContextClassLoader());
    }

    /**
     * 加载SPI实现并按照顺序放在反序列化列表中
     */
    public void loadSPI() {
        for(Deserializer deserializer: ServiceLoader.load(Deserializer.class)) {
            List<Class<?>> typeArguments = TypeUtils.resolveTypeArguments(deserializer.getClass());
            Class<?> targetClass = typeArguments.isEmpty()? Object.class: typeArguments.get(0);
            List<Deserializer> deserializers = typeDeserializers.computeIfAbsent(targetClass, k -> new LinkedList<>());
            deserializers.add(deserializer);
            deserializers.sort(PriorityComparator.INSTANCE);
        }
    }


    public Deserializer getMostCompatible(Class<String> deserializedType) {
        Deserializer<?> deserializer = getHighestPriority(deserializedType);
        if(deserializer == null) {
            deserializer = getLowestPriority(Object.class);
        }
        return deserializer;
    }

    private <T> Deserializer<T> getLowestPriority(Class<?> deserializedType) {
        List<Deserializer<T>> deserializers = get(deserializedType);
        return deserializers.isEmpty()? null: deserializers.get(deserializers.size() - 1);
    }

    /**
     * 获取优先级最高的反序列化实例
     */
    private <T> Deserializer<T> getHighestPriority(Class<?> deserializedType) {
        List<Deserializer<T>> deserializers = get(deserializedType);
        return deserializers.isEmpty()? null: deserializers.get(0);
    }

    /**
     * 获取指定类的所有的实例对象
     */
    private <T> List<Deserializer<T>> get(Class<?> deserializedType) {
        return (List)typeDeserializers.getOrDefault(deserializedType, Collections.emptyList());
    }


}
